#include <string.h>
#include "XRCORE.h"

// unsigned char GDataType = 0;

static unsigned short VerifyBlock(unsigned char *ACardSN, unsigned char *ABlock,
                    unsigned char AMoneyBlock, unsigned char dataType, unsigned char cpuCard)
{   // var
    static unsigned char oMix[5];
    unsigned char oHeader = 0;
    unsigned char oFooter = 0;

    memmove(oMix, ACardSN, 4);
    oMix[4] = 0x5A;

    // ??????? ( ?? 0 / 1 )
    oHeader = BytesXor(ABlock, 1, 14);
    oFooter = BytesAdd(ABlock, 1, 14);

    if (((dataType == 1) || cpuCard) && ((AMoneyBlock) || (!AMoneyBlock && (ABlock[5] == 0xBB)))) {
        oHeader = oHeader ^ BytesXor(oMix, 0, 5);
        oFooter = oFooter + BytesAdd(oMix, 0, 5);
    }
    oFooter = oFooter ^ 0xFF;

    if (( oHeader != ABlock[0] )||( oFooter != ABlock[15] ))
    {   return 1; }

    return 0;
}

// { ????? }
static void SignBlock(unsigned char *ACardSN, unsigned char *ABlock, unsigned char AMoneyBlock, unsigned char dataType, unsigned char cpuCard)
{   // var
    static unsigned char oMix[5];
    unsigned char oHeader = 0;
    unsigned char oFooter = 0;

    memmove(oMix, ACardSN, 4);
    oMix[4] = 0x5A;

    // ??????? ( ?? 0 / 1 )
    oHeader = BytesXor(ABlock, 1, 14);
    oFooter = BytesAdd(ABlock, 1, 14);

    if (((dataType == 1) || cpuCard) && ((AMoneyBlock) || (!AMoneyBlock && (ABlock[5] == 0xBB)))) {
        oHeader = oHeader ^ BytesXor ( oMix, 0, 5 );
        oFooter = oFooter + BytesAdd ( oMix, 0, 5 );
    }

    oFooter = oFooter ^ 0xFF;

    ABlock[0] = oHeader;
    ABlock[15] = oFooter;
}
// { ??????? }
unsigned short DecodeNumBlock ( unsigned char * ACardSN, unsigned char * ABlock, unsigned char dataType, unsigned char cpuCard)
{   // var
    static unsigned short err;

    err = VerifyBlock ( ACardSN, ABlock, 0, dataType, cpuCard);
    if (err != 0) {
        return err;
    }

    // ????????                                     // ????????
    if ((ABlock[6] != BytesAddReverse(ABlock, 1, 5)) || (ABlock[10] != BytesAddReverse(ABlock, 7, 3))) {
        return 1;
    }

    return 0;
}
//?????
void EncodeNumBlock(unsigned char *ABlock, unsigned char oVer, unsigned char *oAuthCode, 
                unsigned char oAffiCode, unsigned char FuncAttr, unsigned char *xSnr, unsigned char *oPin)
{
    ABlock[1]  = oVer;
    ABlock[2]  = oAuthCode[0];
    ABlock[3]  = oAuthCode[1];
    ABlock[4]  = oAffiCode;
    ABlock[5]  = FuncAttr;
    ABlock[7]  = xSnr[0];
    ABlock[8]  = xSnr[1];
    ABlock[9]  = xSnr[2];
    ABlock[11] = oPin[0];
    ABlock[12] = oPin[1];
    ABlock[13] = oPin[2];
    ABlock[14] = oPin[3];

    ABlock[6]  = BytesAddReverse(ABlock, 1, 5);
    ABlock[10] = BytesAddReverse(ABlock, 7, 3);

    ABlock[0]  = BytesXor(ABlock, 1, 14);
    ABlock[15] = BytesAddReverse(ABlock, 1, 14);
}

// { ??????? }
unsigned short DecodeMoneyBlock(unsigned char *ACardSN, unsigned char *ABlock, unsigned int *ABalance, 
                        unsigned short *ATradeSerial, unsigned char dataType, unsigned char cpuCard)
{   // var
    static unsigned short err;

    err = VerifyBlock(ACardSN, ABlock, 1, dataType, cpuCard);
    if (err != 0)
    {   return err; }

    if ((ABlock[1] != BytesAdd(ABlock, 2, 3)) || (ABlock[5] != (ABlock[1] ^ 0xff))) 
    {   return 1; }

    *ABalance     = ((unsigned int)(ABlock[4] << 16)) + ((unsigned int)(ABlock[3] << 8)) + ABlock[2];
    *ATradeSerial = ((unsigned short)(ABlock[9] << 8)) + ABlock[13];

    return 0;
}
// { ??????? }
void EncodeMoneyBlock(unsigned char *ACardSN, unsigned char *ABlock, unsigned int *ABalance, 
                unsigned short *ATradeSerial, unsigned char dataType, unsigned char cpuCard)
{
    ABlock[4] = (unsigned char)(*ABalance >> 16);
    ABlock[3] = (unsigned char)(*ABalance >> 8);
    ABlock[2] = (unsigned char)(*ABalance);

    ABlock[9]  = (unsigned char)(*ATradeSerial >> 8);
    ABlock[13] = (unsigned char)(*ATradeSerial);

    ABlock[1] = BytesAdd(ABlock, 2, 3);
    ABlock[5] = ABlock[1] ^ 0xff;

    SignBlock(ACardSN, ABlock, 1, dataType, cpuCard);
}

// { CPU 验证}
// 0x00: 9F | 90 0F  60 00 00 00 00 00  | 00   00 00 00 00 00 00
// 0x10: [header 55] | 5A 14 [key 14 04 72 C5 66 8C] | [footer 0B] D9 00 00 00 00 00
unsigned short VerifyCPUKeyUnsafe(unsigned char *ACardSN, unsigned char *AFileBuf, unsigned char *APosKey)
{
    static unsigned char oKey[6];
    static unsigned char oI;
    static unsigned char oHeader, oFooter;

    memmove(oKey, &AFileBuf[0x13], 6);

    // 01 23 45 67 89 5A, ?? oKey: 05 51 80 01 05 51
    for (oI = 0; oI < 5; oI++) {
        oKey[oI] = oKey[oI] ^ ( 0x01 + 0x22 * oI );
    }
    oKey[5] = oKey[5] ^ 0x5A;
    // ????
    for (oI = 0; oI < 6; oI++) {
        if (oKey[oI] != APosKey[oI]) {
            return 1;
        }
    }

    oHeader = BytesXor(AFileBuf, 0x11, 8) ^ BytesXor(ACardSN, 0, 4);
    oFooter = BytesAdd(AFileBuf, 0x11, 8) + BytesAdd(ACardSN, 0, 4);

    if ((AFileBuf[0x10] != oHeader) || (AFileBuf[0x19] != oFooter))
    {   return 1; }

    return 0;
}
// { ???????? }
unsigned short GenCPUExtSign(unsigned char *ACardSN, unsigned char *ARand, unsigned char *AKey, unsigned char *ADst)
{
    static unsigned char oI;
    static unsigned char oSrc[8];
    static unsigned char oKey[8];
    static unsigned char oBuf[8];

    memset(ADst, 0, 8);

    // ???8????
    memmove(oSrc, ARand, 4);
    memset(&oSrc[4], 0, 4);

    //oBuf: S0 S1 5A 5A 5A 5A S2 S3
    memmove(oBuf, &ACardSN[2], 2);
    memset(&oBuf[2], 0x5A, 4);
    memmove(&oBuf[6], ACardSN, 2);
    //oKey: K0 K1 K2 K3 K4 K5 5A 5A
    memmove(oKey, AKey, 6);
    memset(&oKey[6], 0x5A, 2);

    // ??8????
    for (oI = 0; oI < 8; oI++) {
        oKey[oI] = oKey[oI] ^ oBuf[oI];
    }

    Des(oSrc, ADst, oKey, 0); // 2022-4-19 18:50:27

    return 0;
}
// { ??????? }
unsigned short DecodeMoneyBlockAll ( unsigned char *ACardSN, unsigned char *ABlock, unsigned int *ABalance, 
                            unsigned short *ATradeSerial,unsigned char *Day, unsigned char *DateUsage, 
                            unsigned char *Month, unsigned short *MonthUsage, unsigned short *DayMoneyUse,
                            unsigned char dataType, unsigned char cpuCard)
{
    static unsigned short err;

    err = VerifyBlock(ACardSN, ABlock, 1, dataType, cpuCard);
    if (err != 0) {
        return err;
    }

    if (ABlock[1] != BytesAdd(ABlock, 2, 3) || ABlock[5] != (ABlock[1] ^ 0xff)) {
        return 1;
    }

    *ABalance     = ((unsigned int)(ABlock[4] << 16)) + ((unsigned int)(ABlock[3] << 8)) + ABlock[2];
    *ATradeSerial = ((unsigned short)(ABlock[9] << 8)) + ABlock[13];
    *DayMoneyUse  = ((unsigned short)(ABlock[8] << 8)) + ABlock[14];
    *MonthUsage   = ((unsigned short)(ABlock[11] << 8)) + ABlock[12];
    *Month = ABlock[10];
    *DateUsage = ABlock[6];
    *Day = ABlock[7];
    return 0;
}

void EncodeMoneyBlockAll ( unsigned char * ACardSN, unsigned char * ABlock, unsigned int *ABalance, 
                        unsigned short *ATradeSerial,unsigned char *Day,unsigned char *DateUsage, 
                        unsigned char *Month, unsigned short *MonthUsage, unsigned short *DayMoneyUse,
                        unsigned char dataType, unsigned char cpuCard)
{
    ABlock[4] = (unsigned char)(*ABalance >> 16);
    ABlock[3] = (unsigned char)(*ABalance >> 8);
    ABlock[2] = (unsigned char)(*ABalance);

    ABlock[9]  = (unsigned char)(*ATradeSerial >> 8);
    ABlock[13] = (unsigned char)(*ATradeSerial);

    ABlock[1]  = BytesAdd(ABlock, 2, 3);
    ABlock[5]  = ABlock[1] ^ 0xff;
    ABlock[6]  = *DateUsage;
    ABlock[7]  = *Day;
    ABlock[8]  = (unsigned char)(*DayMoneyUse >> 8);
    ABlock[14] = (unsigned char)(*DayMoneyUse);
    ABlock[10] = *Month;
    ABlock[11] = (unsigned char)(*MonthUsage >> 8);
    ABlock[12] = (unsigned char)(*MonthUsage);

    SignBlock(ACardSN, ABlock, 1, dataType, cpuCard);
}



